package org.gwt.project.tools;

import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.gwt.project.tools.cpe.Container;
import org.gwt.project.tools.quickfix.Generator;

public class ToolsNature implements IProjectNature {

	private IProject project;
	
	public static final String ID = ToolsPlugin.ID + ".gwtToolsNature";
	
	@Override
	public void configure() throws CoreException {
		
		// Declare variables
		int i = -1;
		IProgressMonitor monitor = new NullProgressMonitor();
		
		// Get builders already configured
		IProjectDescription desc = getProject().getDescription();
		ICommand[] commands = desc.getBuildSpec();

		// Find JDT builder
		for (int j = 0; j < commands.length; ++j) {
			// Get name
			String name = commands[j].getBuilderName();
			// Only add this builder once...
			if (name.equals(ToolsBuilder.ID)) { return; } 
			// Is JDT builder?			
			else if (name.equals(ToolsPlugin.JDT_BUILDER_ID)) { i = j; }
		}
		
		// Validate JDT builder existence
		if(i == -1) {
			Generator.createProblemMarker(
					getProject(),
					Generator.PROJECT,
					"This is not a Java project", 
					IMarker.PRIORITY_HIGH, 
					IMarker.SEVERITY_ERROR, 
					getProject().getName());
			throw ToolsPlugin.asException("'" + getProject().getName() + "' is not a Java project");
		}
		
		// Collect all builders configured for this project
		ICommand[] newCommands = new ICommand[commands.length + 1];
		System.arraycopy(commands, 0, newCommands, 0, commands.length);
		ICommand command = desc.newCommand();
		command.setBuilderName(ToolsBuilder.ID);
		newCommands[newCommands.length - 1] = command;
		// Ensure correct build order
		if( i == 0 || newCommands.length == 2 ) {
			// Move builder i front of JDT builder
			ToolsUtil.swap(newCommands, 0, 1);
		} else {
			// Swap move builder before JDT builder
			ToolsUtil.move(newCommands, i, newCommands.length - 1);
		}
		// Set new build specification
		desc.setBuildSpec(newCommands);
		getProject().setDescription(desc, monitor);
		
		// Create container entry
		Container container = new Container( JavaCore.create(getProject()) );
		IClasspathEntry entry = JavaCore.newContainerEntry(container.getPath(),true);

		// Add container to project classpath
		IJavaProject project =  container.getJavaProject();
		IClasspathEntry[] entries = project.getRawClasspath();
		IClasspathEntry[] newEntries = new IClasspathEntry[entries.length + 1];
		System.arraycopy(entries, 0, newEntries, 0, entries.length);
		newEntries[entries.length] = entry;
		project.setRawClasspath(newEntries, monitor);
		        
	}

	@Override
	public void deconfigure() throws CoreException {
		
		// Declare variables
		IProgressMonitor monitor = new NullProgressMonitor();
				
		// Remove builder from project
		IJavaProject project = JavaCore.create(getProject());
		IClasspathEntry[] entries = project.getRawClasspath();
		for (int i = 0; i < entries.length; ++i) {
			if (entries[i].getPath().equals(new Path(Container.ID))) {
				IClasspathEntry[] newEntries = new IClasspathEntry[entries.length - 1];
				System.arraycopy(entries, 0, newEntries, 0, i);
				System.arraycopy(entries, i + 1, newEntries, i,
						entries.length - i - 1);
				project.setRawClasspath(newEntries, monitor);
				break;
			}
		}
		
		// Remove builder from project
		IProjectDescription description = getProject().getDescription();
		ICommand[] commands = description.getBuildSpec();
		for (int i = 0; i < commands.length; ++i) {
			if (commands[i].getBuilderName().equals(ToolsBuilder.ID)) {
				ICommand[] newCommands = new ICommand[commands.length - 1];
				System.arraycopy(commands, 0, newCommands, 0, i);
				System.arraycopy(commands, i + 1, newCommands, i,
						commands.length - i - 1);
				description.setBuildSpec(newCommands);				
				getProject().setDescription(description, monitor);			
				break;
			}
		}
				
	}
	
	@Override
	public IProject getProject() {
		return project;
	}

	@Override
	public void setProject(IProject project) {
		this.project = project;
	}

}
